Pre-requisites

There two things we need to do before we start the lesson.

  1. Install R: Any of the links on that page should work
  2. Install Rstudio: Choose the option that is suited for your Operating System (OS).

Get familiar with your working environment

When you installed R on your computer, you provide it the tools necessary to process code that is written in R. The Base R installation ships with a simple code editor that can be used to write R scripts. RStudio is a software application that builds on top of your R installation to give you additional functionality to write and manage R code and projects 1. It is by far the most popular integrated development environment (IDE) for R and has several features that are custom made to support data science in R.

There are four different panes on RStudio that you need to get familiar with.

  1. The console: This is the pane that is usually located on the left (at the bottom if you have a script or notebook open) that can be used to type in R commands. The console is a great place to test out lines of code that doesn’t necessarily have to go into the project you are woring on. The console is also the place were the output of your code are printed 2. The console however, is not the place to write any code that you need to rerun since it is not possible to save code that is written in the console as a file. You will need to use the code pane to do that.
  2. The code: This is were you will write the majority of the code for your projects. There are several different formats in which you can write code. This pane only appears if you have an open file that you are currently working on. Click on the button at the top left of R Studio to see the different options. We will use the first two options R Notebook and R Script for most of this course.
  3. The viewer: The pane to the bottom right is where you can view plots rendered by your code, packages that are currently loaded to the environment, access help files, view documents, and access folders on your computer. Click on the tab to scroll through the list and see all the packages that are checked. These are the packages that are pre-loaded with your session. If you don’t know what packages are, don’t worry, we will be covering that very soon.
  4. The environment: The environment pane is the one on the top-right. This is were all the variables and functions that you create are displayed. R Studio provides additional functionality that allows users to click on these variables to view their contents. Click on dropdown you will notice that there are several other packages that are listed there. These are the same as those that are checked in the packages tab on the viewer pane. Selecting one of them will display the entire list of functions that are currently available for you to use.

Ninja Tasks

  1. Create a Numbers Ninja Folder on your local machine
  2. Create an R Notebook “Class_1” and save it in this folder

A quick R Markdown detour

Markdown is a markup language.

From Wikipedia:

In computer text processing, a markup language is a system for annotating a document in a way that is syntactically distinguishable from the text…the whole idea of a mark up language is to avoid the formatting work for the text, as the tags in the mark up language serve the purpose to format the appropriate text (like a header or beginning of a next para…etc.). Every tag used in a Markup language has a property to format the text we write. -

Hyper Text Markup Language(HTML) is perhaps the most well-known markup language out there 3. It is used to render content on websites. Go ahead and right click on any webpage and click on inspect to open up the web inspector to view the underlying HTML code that was used to generate it. Markdown is a more human friendly (but limited) version of HTML. Markdown uses simple and easy to read tags to markup text which is compiled (by your computer) into HTML that can be used to render webpages. Making it easier to create content that can be rendered on a webpage for those who are unfamiliar with HTML.

R Markdown is a package in that allows us to combine markdown with R code. Using R Markdown we can create a wide variety of easy to read and reproduce R documents that contain both code and nicely formatted. This online R notebook is a case in point.

In addition to using markdown to markup text, R Markdown documents also uses R MarkdownYAML. This is the section right at the top of the notebook that is separated by the ---. This is the part of the document were you specify the title and other characteristics of the report.

Here are a few references to keep handy

  1. R Markdown: The definitive guide
  2. R Markdown cheatsheet

Ninja Tasks

  1. Create an H2 level header with title Class 1 Exercises
  2. Write the following text: “The list below shows the exercises for this class”
  3. Create an ordered list with following list items: “1. Practice Shortcuts” “2. Practice dplyr”
  4. Click on the preview button at the top left of the IDE to preview your notebook

Shortcuts

Before we move on, lets learn a few shortcuts.

  1. Cmd + Option + I or Ctrl + Alt + I: Insert a chunk in markdown/notebook etc
  2. Option + - or Alt + -: Enter the assignment operator
  3. Cmd + Enter or Ctrl + Enter: Run current line/selection
  4. Cmd + Shift + Enter Ctrl + Shift + Enter: Run the entire script if it is a script file or the current chunk in the case of a notebook.
  5. Cmd + Shift + M or Ctrl + Shift + M: Insert pipe operator

You can find more shortcut keys here

Ninja Tasks

  1. Use all the shortcuts to do the following task: create a new code chunk => assign the string “Hello World” to myFirstVar variable => run the line of code => add a print command using print(myFirstVar) => run the entire chunk

Packages

Packages that make our job as coders easier by extending the functionality of base R. Each package contains a collection of functions that we can use in our code without having to worry about needing to write and maintain them ourselves. In addition to functions, packages can also contain data or point database api (such wbstats which points to the World Banks data). R has an extremely rich, well maintained ecosystem of packages that contain functions and data that are relevant to almost any academic (or even trivial) topics of interest.

Ninja Tasks

  1. Install the following packages - tidyverse and nycflights13 using the package tab in the viewer pane (use the button)
  2. Use the library() function to load these two packages in the Class 1 notebook
  3. Check the packages tab on your viewer to see if these packages are checked (i.e. loaded to our current environment)
  4. Check the Global Environment dropdown to see that these are listed.

Tidyverse

The tidyverse is a collection of packages that follow the tidy tools philosophy.

The Tidy Tools Manifesto by Hadley Wickham, describes the four basic principles of a tidy API as follows:

  1. Reuse existing data structures.
  2. Compose simple functions with the pipe.
  3. Embrace functional programming.
  4. Design for humans.

There are two overarching programming concepts here that are important for us to note - composition and the use of declaritive instead of imperative code. Composition is simply the use of several smaller functions to create a more complex function. The tidyverse achieves composition through the use of pipes (%>%). We will learn about pipes relatively soon.

According to Wikipedia:

In computer science, declarative programming is a programming paradigm—a style of building the structure and elements of computer programs—that expresses the logic of a computation without describing its control flow.

This video explains this further using the real-world example of a car (albeit from the persepective of React a Javascript library).

The tidyverse packages are characterized by their extensive use of pipes to break down complex functions into simpler pieces that are easier to to read and understand. We will learn about pipes shortly.

Ninja Tasks

  1. Read the tidy tools manifesto

nycflight13 data

We will be using the nycflights13 datasets package to learn data manipulation. The package contains relational datasets that offer information on all the flights that took off from 3 airports in NYC (EWR, JFK, LGA) in 2013. The different datasets in the package are as follows:

  1. airlines: Names of the different airline carriers
  2. airports: Meta data on the airports in the dataset
  3. flights: Data on all the flights that departed NYC in 2013
  4. planes: Meta data on the planes (their make, capacity etc)
  5. weather: Weather at the three NYC airports on all days of 2013

For this notebook we will be using only the flights data.

Data Manipulation using dplyr

dplyr is a package in the tidyverse collection. It provides elegant and easy to understand functions for manipulating data in R.

Keep this data wrangling cheatsheet open on your browser as a ready reference for the rest of the notebook.

Tibbles

A tibble is a tidy version of a data.frame. It adds a few extra features (through two new classes) that give it a few advantages over data.frames.

Ninja Tasks

  1. Create a tibble (of your choice) with three observations and three variables.
  2. Show the class and structure of the tibble you created.
  3. Convert the mtcars data set to a tibble.

🏆Solution🏆

Lets create a tibble using the tibble() command. Check out the code below. Each input in the tibble command is a column. Notice how I have used both column vectors created within tibble() and an externally created the vector hobby inside the command.

hobbies <-  c("dancing", "hiking", "reading")
myFavoriteThings <- tibble(gadgets = c("Pixel", "Kindle", "Vaccum Cleaner"), books = c("Das Kapital", "Harry Potter", "Enid Blyton"), hobbies)
myFavoriteThings

Lets checkout the structure using the str() command.

str(myFavoriteThings)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   3 obs. of  3 variables:
 $ gadgets: chr  "Pixel" "Kindle" "Vaccum Cleaner"
 $ books  : chr  "Das Kapital" "Harry Potter" "Enid Blyton"
 $ hobbies: chr  "dancing" "hiking" "reading"

The tidyverse also provides a function called glimpse() to do the same thing as str(). Notice the differences between the outputs from the two commands.

glimpse(myFavoriteThings)
Observations: 3
Variables: 3
$ gadgets <chr> "Pixel", "Kindle", "Vaccum Cleaner"
$ books   <chr> "Das Kapital", "Harry Potter", "Enid Blyton"
$ hobbies <chr> "dancing", "hiking", "reading"

You can access the class of any object in R using the class() command. Notice how there are three classes for a tibble - “tbl_df”, “df” and “data.frame”. Tibbles really are just data.frames with some added functionality on top that is provided by the df and tbl_df classes.

class(myFavoriteThings)
[1] "tbl_df"     "tbl"        "data.frame"

mtcars is a part of the datasets package that is preloaded in R. Lets first look at its structure using str()

str(mtcars)
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

As you can see the class of mtcars is a data.frame and not a tibble. We can convert it to a tibble using the as_tibble() command. Below, I have used this command to create a new tibble called mtTibble. The output shows it structure. Notice that now we have the two additional classes “df” and “tbl_df” that characterize tibbles.

mtTibble <- as_tibble(mtcars)
str(mtTibble)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

The Pipe Operator

The pipe operator is a part of the magittr package. You can create one using the shortcuts you learnt earlier (Cmd + Shift + M or Ctrl + Shift + M). The pipe transfers the values that are to the left of it to the right side. While this might seem a bit abstract at this point, %>% is an excellent way to break down code into smaller pieces that are easier to read and maintain.

Ninja Tasks

  1. Calculate the square root of the sum of all even numbers from 0 to 200 and create a sequence that goes from the square root to twice its value.
  2. Repeat the task using base commands.

🏆Solution🏆

First lets do it using pipes. Notice the use of the dot on the last line of the code. When using pipes the . is used to refer explicitly to the data on the left side of the pipe. We do this so that we can perform operation on it. In our case, we need to create a sequence that goes from the left-hand side value to twice its value and we acheive this using . * 2. Note that we could have used the dot notation to refer to the data on the left hand side explicitly for each command, however, dplyr automatically assumes that you are passing the data from the left side saving us the trouble. We only need to use a . if we need to perform an operation or use it explicitly as a function argument.

##create a sequence of even numbers from 0 to 200
seq(from = 0, to = 200, by = 2) %>% 
    ##calculate the sum of all values in the previous vector
    sum() %>% 
    ##calculate the square root of the value from the sum operation
    sqrt() %>% 
    ##create a new seq from the previous value to twice its value
    seq(from = ., to = . * 2, by = 2)
 [1] 100.4988 102.4988 104.4988 106.4988 108.4988 110.4988 112.4988 114.4988 116.4988 118.4988 120.4988
[12] 122.4988 124.4988 126.4988 128.4988 130.4988 132.4988 134.4988 136.4988 138.4988 140.4988 142.4988
[23] 144.4988 146.4988 148.4988 150.4988 152.4988 154.4988 156.4988 158.4988 160.4988 162.4988 164.4988
[34] 166.4988 168.4988 170.4988 172.4988 174.4988 176.4988 178.4988 180.4988 182.4988 184.4988 186.4988
[45] 188.4988 190.4988 192.4988 194.4988 196.4988 198.4988 200.4988

Now lets do this without the pipes. Notice how the base command combines multiple steps i.e. sum(), sqrt() and seq() into a single command. Code such as this is harder to read, understand and debug compared to the version that uses %>%.

##create the a sequence, calculate its sum and find the square root
sqrtValue <- sqrt(sum(seq(from = 1, to = 200, by = 2)))
##create a sequence
seq(from = sqrtValue, to = 2 * sqrtValue, by = 2)
 [1] 100 102 104 106 108 110 112 114 116 118 120 122 124 126 128 130 132 134 136 138 140 142 144 146 148
[26] 150 152 154 156 158 160 162 164 166 168 170 172 174 176 178 180 182 184 186 188 190 192 194 196 198
[51] 200

Filter

Filter is the dplyr verb for subsetting rows of data based on a particular condition.

Ninja Tasks

  1. Which flight out of JFK was the most delayed in 2013?
  2. Answer the previous question without using dplyr or pipes.
  3. What were the 5 longest flights (in air time) from NYC in 2013?

🏆Solution🏆

Lets find the most delayed flight out of JFK

flights %>% 
    ##filter all flights from JFK
    filter(origin == "JFK") %>% 
    ##find the flight that had the maximum departure delay
    filter(dep_delay == max(dep_delay, na.rm = T))

Lets try to do this using base R. Notice how the code is far less readable in this case.

jfkFlights <- flights[flights$origin == "JFK", ]
maxDelay <- max(jfkFlights$dep_delay, na.rm = T)
jfkFlights[jfkFlights$dep_delay == maxDelay & !is.na(jfkFlights$dep_delay), ]

dplyr also ships with helper function. We can use one of these top_n to find the flights that had the highest air times.

flights %>% 
    top_n(air_time, n = 5)

Select

Select is a dplyr verb that is used for subsetting columns.

Ninja Tasks

  1. Select all the columns that are relevant for arrival and departure delays using a utility function (refer to cheat sheet)

🏆Solution🏆

We can combine the select verb with the contain helper function to achieve this task.

flights %>% 
    select(contains("delay"))

Arrange

Arrange is a verb that arranges the rows based on the values of a particular column i.e. performs a sort.

Ninja Tasks

  1. Filter the top 10 most delayed flights in JFK and arrange by dep_delay (highest to lowest)

🏆Solution🏆

Note that I have

flights %>% 
    ##arrange dep_delay in descending order (high to low)
    arrange(desc(dep_delay)) %>% 
    ##filter the first 10 rows using row_number()
    filter(row_number() <= 10) %>% 
    ##select the relevant columns
    select(month, day, origin, dep_delay)

Mutate

Mutate changes a tibble by adding a new column vector or changing an existing one.

Ninja Tasks

  1. Create a new variable called total_delay that is the sum of the arrival delay and departure delay
  2. Do the same task using Base R

🏆Solution🏆

flights %>% 
    ##combine arrival delay and departure delay
    mutate(tot_delay = arr_delay + dep_delay) %>% 
    ##select all the delay columns
    select(contains("delay"))

Now lets repeat this using Base R.

flights$tot_delay <- flights$arr_delay + flights$dep_delay
flights[names(flights) %in% c("dep_delay", "arr_delay", "tot_delay")]

Group and Summarise

group_by() categorizes the data based on the grouping variable, while summarise calculates summary statistics within these groups.

Ninja Tasks

  1. Create a summary table with the following characteristics for each of the origin airports.
    • Number of flights
    • Number of unique carriers
    • Average departure delays
    • Average flight times (air time)
    • Average arrival delays

🏆Solution🏆

Note the use of the functions n() and n_distinct(). Look up the help to understand what they do.

flights %>% 
    ##group the data by the origin (JFK, EWR, LGA)
    group_by(origin) %>% 
    ##calculate the summary statistics of interest
    summarise(nFlights = n(),
              nCarriers = n_distinct(carrier),
              meanDepDelay = mean(dep_delay, na.rm = T),
              meanAirTime = mean(air_time, na.rm = T),
              meanArrDelay = mean(arr_delay, na.rm = T))
NA

  1. The techinical term for this type of software application is: integrated development environment(IDE).

  2. This is true for all formats other than those that use R Markdown. In the case script formats that use R markdown the output is printed within the script rather than in the console.

  3. Some other examples include - TeX and LaTeX. TeX is the markup language that used as a typesetting system in computers for high quality books. LaTeX is used extensively in academia to create documents.

LS0tCnRpdGxlOiAnTnVtYmVycyBOaW5qYTogQ2xhc3MgMScKYXV0aG9yOiB8CiAgfCBIYXJpIFN1Ymhhc2gKICB8IERhdGEgU2NpZW50aXN0IEBOUkdJCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBoaWdobGlnaHQ6IGthdGUKICAgIHNtYXJ0OiB5ZXMKICAgIHRoZW1lOiBjb3NtbwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIGluY2x1ZGVzOiBhc3NldHMvaGVhZGVyLmh0bWwKICBnaXRodWJfZG9jdW1lbnQ6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKY3NzOiBhc3NldHMvY3VzdG9tLmNzcwotLS0KCgo8IS0tIGBgYHtyLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfSAtLT4KPCEtLSBodG1sdG9vbHM6OmltZyhzcmMgPSBrbml0cjo6aW1hZ2VfdXJpKCdhc3NldHMvbmluamEtbG9nby5qcGcnKSwgIC0tPgo8IS0tICAgICAgICAgICAgICAgIGFsdCA9ICdsb2dvJywgIC0tPgo8IS0tICAgICAgICAgICAgICAgIHN0eWxlID0gJ3Bvc2l0aW9uOmFic29sdXRlOyB0b3A6NSU7IHJpZ2h0OjUlOyBwYWRkaW5nOjEwcHg7IHdpZHRoOjEyJScpIC0tPgo8IS0tIGBgYCAtLT4KCjxkaXYgY2xhc3M9ImNvbXBsZXRlZCI+CiMjUHJlLXJlcXVpc2l0ZXMKVGhlcmUgdHdvIHRoaW5ncyB3ZSBuZWVkIHRvIGRvIGJlZm9yZSB3ZSBzdGFydCB0aGUgbGVzc29uLgoKMS4gW0luc3RhbGwgUl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvKTogQW55IG9mIHRoZSBsaW5rcyBvbiB0aGF0IHBhZ2Ugc2hvdWxkIHdvcmsKMi4gW0luc3RhbGwgUnN0dWRpb10oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcHJvZHVjdHMvcnN0dWRpby9kb3dubG9hZC8pOiBDaG9vc2UgdGhlIG9wdGlvbiB0aGF0IGlzIHN1aXRlZCBmb3IgeW91ciBPcGVyYXRpbmcgU3lzdGVtIChPUykuCgo8ZGl2IGNsYXNzPSJmdWxsLXdpZHRoIj4KYGBge3IsIGVjaG89RkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJhc3NldHMvYnJhZGVuLWNvbGx1bS04Nzg3NC11bnNwbGFzaC5qcGciKQpgYGAKPC9kaXY+CiMjR2V0IGZhbWlsaWFyIHdpdGggeW91ciB3b3JraW5nIGVudmlyb25tZW50CldoZW4geW91IGluc3RhbGxlZCAhW1JdKGFzc2V0cy9SLnBuZykgb24geW91ciBjb21wdXRlciwgeW91IHByb3ZpZGUgaXQgdGhlIHRvb2xzIG5lY2Vzc2FyeSB0byBwcm9jZXNzIGNvZGUgdGhhdCBpcyB3cml0dGVuIGluIFIuIFRoZSBCYXNlIFIgaW5zdGFsbGF0aW9uIHNoaXBzIHdpdGggYSBzaW1wbGUgY29kZSBlZGl0b3IgdGhhdCBjYW4gYmUgdXNlZCB0byB3cml0ZSBSIHNjcmlwdHMuICFbUlN0dWRpb10oYXNzZXRzL1JzdHVkaW8ucG5nKSBpcyBhIHNvZnR3YXJlIGFwcGxpY2F0aW9uIHRoYXQgYnVpbGRzIG9uIHRvcCBvZiB5b3VyIFIgaW5zdGFsbGF0aW9uIHRvIGdpdmUgeW91IGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSB0byB3cml0ZSBhbmQgbWFuYWdlIFIgY29kZSBhbmQgcHJvamVjdHMgW14xXS4gSXQgaXMgYnkgZmFyIHRoZSBtb3N0IHBvcHVsYXIgaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCAoSURFKSBmb3IgUiBhbmQgaGFzIHNldmVyYWwgZmVhdHVyZXMgdGhhdCBhcmUgY3VzdG9tIG1hZGUgdG8gc3VwcG9ydCBkYXRhIHNjaWVuY2UgaW4gUi4KClRoZXJlIGFyZSBmb3VyIGRpZmZlcmVudCBwYW5lcyBvbiBSU3R1ZGlvIHRoYXQgeW91IG5lZWQgdG8gZ2V0IGZhbWlsaWFyIHdpdGguCgoxLiBUaGUgY29uc29sZTogVGhpcyBpcyB0aGUgcGFuZSB0aGF0IGlzIHVzdWFsbHkgbG9jYXRlZCBvbiB0aGUgbGVmdCAoYXQgdGhlIGJvdHRvbSBpZiB5b3UgaGF2ZSBhIHNjcmlwdCBvciBub3RlYm9vayBvcGVuKSB0aGF0IGNhbiBiZSB1c2VkIHRvIHR5cGUgaW4gUiBjb21tYW5kcy4gVGhlIGNvbnNvbGUgaXMgYSBncmVhdCBwbGFjZSB0byB0ZXN0IG91dCBsaW5lcyBvZiBjb2RlIHRoYXQgZG9lc24ndCBuZWNlc3NhcmlseSBoYXZlIHRvIGdvIGludG8gdGhlIHByb2plY3QgeW91IGFyZSB3b3Jpbmcgb24uIFRoZSBjb25zb2xlIGlzIGFsc28gdGhlIHBsYWNlIHdlcmUgdGhlIG91dHB1dCBvZiB5b3VyIGNvZGUgYXJlIHByaW50ZWQgW14yXS4gVGhlIGNvbnNvbGUgaG93ZXZlciwgaXMgbm90IHRoZSBwbGFjZSB0byB3cml0ZSBhbnkgY29kZSB0aGF0IHlvdSBuZWVkIHRvIHJlcnVuIHNpbmNlIGl0IGlzIG5vdCBwb3NzaWJsZSB0byBzYXZlIGNvZGUgdGhhdCBpcyB3cml0dGVuIGluIHRoZSBjb25zb2xlIGFzIGEgZmlsZS4gWW91IHdpbGwgbmVlZCB0byB1c2UgdGhlIGNvZGUgcGFuZSB0byBkbyB0aGF0LgoyLiBUaGUgY29kZTogVGhpcyBpcyB3ZXJlIHlvdSB3aWxsIHdyaXRlIHRoZSBtYWpvcml0eSBvZiB0aGUgY29kZSBmb3IgeW91ciBwcm9qZWN0cy4gVGhlcmUgYXJlIHNldmVyYWwgZGlmZmVyZW50IGZvcm1hdHMgaW4gd2hpY2ggeW91IGNhbiB3cml0ZSBjb2RlLiBUaGlzIHBhbmUgb25seSBhcHBlYXJzIGlmIHlvdSBoYXZlIGFuIG9wZW4gZmlsZSB0aGF0IHlvdSBhcmUgY3VycmVudGx5IHdvcmtpbmcgb24uIENsaWNrIG9uIHRoZSAhW10oYXNzZXRzL3NjcmlwdHMucG5nKSBidXR0b24gYXQgdGhlIHRvcCBsZWZ0IG9mIFIgU3R1ZGlvIHRvIHNlZSB0aGUgZGlmZmVyZW50IG9wdGlvbnMuIFdlIHdpbGwgdXNlIHRoZSBmaXJzdCB0d28gb3B0aW9ucyBSIE5vdGVib29rIGFuZCBSIFNjcmlwdCBmb3IgbW9zdCBvZiB0aGlzIGNvdXJzZS4KMy4gVGhlIHZpZXdlcjogVGhlIHBhbmUgdG8gdGhlIGJvdHRvbSByaWdodCBpcyB3aGVyZSB5b3UgY2FuIHZpZXcgcGxvdHMgcmVuZGVyZWQgYnkgeW91ciBjb2RlLCBwYWNrYWdlcyB0aGF0IGFyZSBjdXJyZW50bHkgbG9hZGVkIHRvIHRoZSBlbnZpcm9ubWVudCwgYWNjZXNzIGhlbHAgZmlsZXMsIHZpZXcgZG9jdW1lbnRzLCBhbmQgYWNjZXNzIGZvbGRlcnMgb24geW91ciBjb21wdXRlci4gQ2xpY2sgb24gdGhlICFbXShhc3NldHMvcGFja2FnZXMucG5nKSB0YWIgdG8gc2Nyb2xsIHRocm91Z2ggdGhlIGxpc3QgYW5kIHNlZSBhbGwgdGhlIHBhY2thZ2VzIHRoYXQgYXJlIGNoZWNrZWQuIFRoZXNlIGFyZSB0aGUgcGFja2FnZXMgdGhhdCBhcmUgcHJlLWxvYWRlZCB3aXRoIHlvdXIgc2Vzc2lvbi4gSWYgeW91IGRvbid0IGtub3cgd2hhdCBwYWNrYWdlcyBhcmUsIGRvbid0IHdvcnJ5LCB3ZSB3aWxsIGJlIGNvdmVyaW5nIHRoYXQgdmVyeSBzb29uLgo0LiBUaGUgZW52aXJvbm1lbnQ6IFRoZSBlbnZpcm9ubWVudCBwYW5lIGlzIHRoZSBvbmUgb24gdGhlIHRvcC1yaWdodC4gVGhpcyBpcyB3ZXJlIGFsbCB0aGUgdmFyaWFibGVzIGFuZCBmdW5jdGlvbnMgdGhhdCB5b3UgY3JlYXRlIGFyZSBkaXNwbGF5ZWQuIFIgU3R1ZGlvIHByb3ZpZGVzIGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSB0aGF0IGFsbG93cyB1c2VycyB0byBjbGljayBvbiB0aGVzZSB2YXJpYWJsZXMgdG8gdmlldyB0aGVpciBjb250ZW50cy4gQ2xpY2sgb24gIVtdKGFzc2V0cy9nbG9iYWwgZW52aXJvbi5wbmcpIGRyb3Bkb3duIHlvdSB3aWxsIG5vdGljZSB0aGF0IHRoZXJlIGFyZSBzZXZlcmFsIG90aGVyIHBhY2thZ2VzIHRoYXQgYXJlIGxpc3RlZCB0aGVyZS4gVGhlc2UgYXJlIHRoZSBzYW1lIGFzIHRob3NlIHRoYXQgYXJlIGNoZWNrZWQgaW4gdGhlIHBhY2thZ2VzIHRhYiBvbiB0aGUgdmlld2VyIHBhbmUuIFNlbGVjdGluZyBvbmUgb2YgdGhlbSB3aWxsIGRpc3BsYXkgdGhlIGVudGlyZSBsaXN0IG9mIGZ1bmN0aW9ucyB0aGF0IGFyZSBjdXJyZW50bHkgYXZhaWxhYmxlIGZvciB5b3UgdG8gdXNlLgoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIENyZWF0ZSBhIE51bWJlcnMgTmluamEgRm9sZGVyIG9uIHlvdXIgbG9jYWwgbWFjaGluZQoyLiBDcmVhdGUgYW4gUiBOb3RlYm9vayAiQ2xhc3NfMSIgYW5kIHNhdmUgaXQgaW4gdGhpcyBmb2xkZXIKClteMV06IFRoZSB0ZWNoaW5pY2FsIHRlcm0gZm9yIHRoaXMgdHlwZSBvZiBzb2Z0d2FyZSBhcHBsaWNhdGlvbiBpczogW2ludGVncmF0ZWQgZGV2ZWxvcG1lbnQgZW52aXJvbm1lbnRdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0ludGVncmF0ZWRfZGV2ZWxvcG1lbnRfZW52aXJvbm1lbnQpKElERSkuCgpbXjJdOiBUaGlzIGlzIHRydWUgZm9yIGFsbCBmb3JtYXRzIG90aGVyIHRoYW4gdGhvc2UgdGhhdCB1c2UgUiBNYXJrZG93bi4gSW4gdGhlIGNhc2Ugc2NyaXB0IGZvcm1hdHMgdGhhdCB1c2UgUiBtYXJrZG93biB0aGUgb3V0cHV0IGlzIHByaW50ZWQgd2l0aGluIHRoZSBzY3JpcHQgcmF0aGVyIHRoYW4gaW4gdGhlIGNvbnNvbGUuCgojI0EgcXVpY2sgUiBNYXJrZG93biBkZXRvdXIKTWFya2Rvd24gaXMgYSBtYXJrdXAgbGFuZ3VhZ2UuCgpGcm9tIFtXaWtpcGVkaWFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01hcmt1cF9sYW5ndWFnZSk6Cgo+SW4gY29tcHV0ZXIgdGV4dCBwcm9jZXNzaW5nLCBhIG1hcmt1cCBsYW5ndWFnZSBpcyBhIHN5c3RlbSBmb3IgYW5ub3RhdGluZyBhIGRvY3VtZW50IGluIGEgd2F5IHRoYXQgaXMgc3ludGFjdGljYWxseSBkaXN0aW5ndWlzaGFibGUgZnJvbSB0aGUgdGV4dC4uLnRoZSB3aG9sZSBpZGVhIG9mIGEgbWFyayB1cCBsYW5ndWFnZSBpcyB0byBhdm9pZCB0aGUgZm9ybWF0dGluZyB3b3JrIGZvciB0aGUgdGV4dCwgYXMgdGhlIHRhZ3MgaW4gdGhlIG1hcmsgdXAgbGFuZ3VhZ2Ugc2VydmUgdGhlIHB1cnBvc2UgdG8gZm9ybWF0IHRoZSBhcHByb3ByaWF0ZSB0ZXh0IChsaWtlIGEgaGVhZGVyIG9yIGJlZ2lubmluZyBvZiBhIG5leHQgcGFyYS4uLmV0Yy4pLiBFdmVyeSB0YWcgdXNlZCBpbiBhIE1hcmt1cCBsYW5ndWFnZSBoYXMgYSBwcm9wZXJ0eSB0byBmb3JtYXQgdGhlIHRleHQgd2Ugd3JpdGUuIC0gCgo8c3BhbiBjbGFzcz0iaGlnaGxpZ2h0Ij5IeXBlciBUZXh0IE1hcmt1cCBMYW5ndWFnZTwvc3Bhbj4oW0hUTUxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0hUTUwpKSBpcyBwZXJoYXBzIHRoZSBtb3N0IHdlbGwta25vd24gbWFya3VwIGxhbmd1YWdlIG91dCB0aGVyZSBbXjNdLiBJdCBpcyB1c2VkIHRvIHJlbmRlciBjb250ZW50IG9uIHdlYnNpdGVzLiBHbyBhaGVhZCBhbmQgcmlnaHQgY2xpY2sgb24gYW55IHdlYnBhZ2UgYW5kIGNsaWNrIG9uIGluc3BlY3QgdG8gb3BlbiB1cCB0aGUgd2ViIGluc3BlY3RvciB0byB2aWV3IHRoZSB1bmRlcmx5aW5nIEhUTUwgY29kZSB0aGF0IHdhcyB1c2VkIHRvIGdlbmVyYXRlIGl0LiA8c3BhbiBjbGFzcz0iaGlnaGxpZ2h0Ij5NYXJrZG93bjwvc3Bhbj4gaXMgYSBtb3JlIGh1bWFuIGZyaWVuZGx5IChidXQgbGltaXRlZCkgdmVyc2lvbiBvZiBIVE1MLiBNYXJrZG93biB1c2VzIHNpbXBsZSBhbmQgZWFzeSB0byByZWFkIHRhZ3MgdG8gbWFya3VwIHRleHQgd2hpY2ggaXMgY29tcGlsZWQgKGJ5IHlvdXIgY29tcHV0ZXIpIGludG8gSFRNTCB0aGF0IGNhbiBiZSB1c2VkIHRvIHJlbmRlciB3ZWJwYWdlcy4gTWFraW5nIGl0IGVhc2llciB0byBjcmVhdGUgY29udGVudCB0aGF0IGNhbiBiZSByZW5kZXJlZCBvbiBhIHdlYnBhZ2UgZm9yIHRob3NlIHdobyBhcmUgdW5mYW1pbGlhciB3aXRoIEhUTUwuIAoKPHNwYW4gY2xhc3M9ImhpZ2hsaWdodCI+UiBNYXJrZG93bjwvc3Bhbj4gaXMgYSBwYWNrYWdlIGluIHRoYXQgYWxsb3dzIHVzIHRvIGNvbWJpbmUgbWFya2Rvd24gd2l0aCBSIGNvZGUuIFVzaW5nIFIgTWFya2Rvd24gd2UgY2FuIGNyZWF0ZSBhIHdpZGUgdmFyaWV0eSBvZiBlYXN5IHRvIHJlYWQgYW5kIHJlcHJvZHVjZSBSIGRvY3VtZW50cyB0aGF0IGNvbnRhaW4gYm90aCBjb2RlIGFuZCBuaWNlbHkgZm9ybWF0dGVkLiBUaGlzIG9ubGluZSBSIG5vdGVib29rIGlzIGEgY2FzZSBpbiBwb2ludC4gCgpJbiBhZGRpdGlvbiB0byB1c2luZyBtYXJrZG93biB0byBtYXJrdXAgdGV4dCwgUiBNYXJrZG93biBkb2N1bWVudHMgYWxzbyB1c2VzIDxzcGFuIGNsYXNzPSJoaWdobGlnaHQiPlIgTWFya2Rvd248L3NwYW4+W1lBTUxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1lBTUwpPC9zcGFuPi4gVGhpcyBpcyB0aGUgc2VjdGlvbiByaWdodCBhdCB0aGUgdG9wIG9mIHRoZSBub3RlYm9vayB0aGF0IGlzIHNlcGFyYXRlZCBieSB0aGUgYC0tLWAuIFRoaXMgaXMgdGhlIHBhcnQgb2YgdGhlIGRvY3VtZW50IHdlcmUgeW91IHNwZWNpZnkgdGhlIHRpdGxlIGFuZCBvdGhlciBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIHJlcG9ydC4KCkhlcmUgYXJlIGEgZmV3IHJlZmVyZW5jZXMgdG8ga2VlcCBoYW5keQoKMS4gW1IgTWFya2Rvd246IFRoZSBkZWZpbml0aXZlIGd1aWRlXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vKQoyLiBbUiBNYXJrZG93biBjaGVhdHNoZWV0XShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNi8wMy9ybWFya2Rvd24tY2hlYXRzaGVldC0yLjAucGRmKQoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIENyZWF0ZSBhbiBIMiBsZXZlbCBoZWFkZXIgd2l0aCB0aXRsZSBDbGFzcyAxIEV4ZXJjaXNlcwoyLiBXcml0ZSB0aGUgZm9sbG93aW5nIHRleHQ6ICJUaGUgbGlzdCBiZWxvdyBzaG93cyB0aGUgZXhlcmNpc2VzIGZvciB0aGlzIGNsYXNzIgozLiBDcmVhdGUgYW4gb3JkZXJlZCBsaXN0IHdpdGggZm9sbG93aW5nIGxpc3QgaXRlbXM6ICIxLiBQcmFjdGljZSBTaG9ydGN1dHMiICIyLiBQcmFjdGljZSBkcGx5ciIKNC4gQ2xpY2sgb24gdGhlIHByZXZpZXcgYnV0dG9uIGF0IHRoZSB0b3AgbGVmdCBvZiB0aGUgSURFIHRvIHByZXZpZXcgeW91ciBub3RlYm9vawoKW14zXTogU29tZSBvdGhlciBleGFtcGxlcyBpbmNsdWRlIC0gW1RlWF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVGVYKSBhbmQgW0xhVGVYXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MYVRlWCkuIFRlWCBpcyB0aGUgbWFya3VwIGxhbmd1YWdlIHRoYXQgdXNlZCBhcyBhIFt0eXBlc2V0dGluZyBzeXN0ZW1dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1R5cGVzZXR0aW5nKSBpbiBjb21wdXRlcnMgZm9yIGhpZ2ggcXVhbGl0eSBib29rcy4gTGFUZVggaXMgdXNlZCBleHRlbnNpdmVseSBpbiBhY2FkZW1pYSB0byBjcmVhdGUgZG9jdW1lbnRzLiAKCiMjU2hvcnRjdXRzCkJlZm9yZSB3ZSBtb3ZlIG9uLCBsZXRzIGxlYXJuIGEgZmV3IHNob3J0Y3V0cy4KCjEuIGBDbWQgKyBPcHRpb24gKyBJYCBvciBgQ3RybCArIEFsdCArIElgOiBJbnNlcnQgYSBjaHVuayBpbiBtYXJrZG93bi9ub3RlYm9vayBldGMKMi4gYE9wdGlvbiArIC1gIG9yIGBBbHQgKyAtYDogRW50ZXIgdGhlIGFzc2lnbm1lbnQgb3BlcmF0b3IKMy4gYENtZCArIEVudGVyYCBvciBgQ3RybCArIEVudGVyYDogUnVuIGN1cnJlbnQgbGluZS9zZWxlY3Rpb24KNC4gYENtZCArIFNoaWZ0ICsgRW50ZXJgIGBDdHJsICsgU2hpZnQgKyBFbnRlcmA6IFJ1biB0aGUgZW50aXJlIHNjcmlwdCBpZiBpdCBpcyBhIHNjcmlwdCBmaWxlIG9yIHRoZSBjdXJyZW50IGNodW5rIGluIHRoZSBjYXNlIG9mIGEgbm90ZWJvb2suCjUuIGBDbWQgKyBTaGlmdCArIE1gIG9yIGBDdHJsICsgU2hpZnQgKyBNYDogSW5zZXJ0IHBpcGUgb3BlcmF0b3IKCllvdSBjYW4gZmluZCBtb3JlIHNob3J0Y3V0IGtleXMgW2hlcmVdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA3MTE4NTMtS2V5Ym9hcmQtU2hvcnRjdXRzKQoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIFVzZSBhbGwgdGhlIHNob3J0Y3V0cyB0byBkbyB0aGUgZm9sbG93aW5nIHRhc2s6IGNyZWF0ZSBhIG5ldyBjb2RlIGNodW5rID0+IGFzc2lnbiB0aGUgc3RyaW5nICJIZWxsbyBXb3JsZCIgdG8gYG15Rmlyc3RWYXJgIHZhcmlhYmxlID0+IHJ1biB0aGUgbGluZSBvZiBjb2RlID0+IGFkZCBhIHByaW50IGNvbW1hbmQgdXNpbmcgYHByaW50KG15Rmlyc3RWYXIpYCA9PiBydW4gdGhlIGVudGlyZSBjaHVuawoKIyNQYWNrYWdlcwpQYWNrYWdlcyB0aGF0IG1ha2Ugb3VyIGpvYiBhcyBjb2RlcnMgZWFzaWVyIGJ5IGV4dGVuZGluZyB0aGUgZnVuY3Rpb25hbGl0eSBvZiBiYXNlIFIuIEVhY2ggcGFja2FnZSBjb250YWlucyBhIGNvbGxlY3Rpb24gb2YgZnVuY3Rpb25zIHRoYXQgd2UgY2FuIHVzZSBpbiBvdXIgY29kZSB3aXRob3V0IGhhdmluZyB0byB3b3JyeSBhYm91dCBuZWVkaW5nIHRvIHdyaXRlIGFuZCBtYWludGFpbiB0aGVtIG91cnNlbHZlcy4gSW4gYWRkaXRpb24gdG8gZnVuY3Rpb25zLCBwYWNrYWdlcyBjYW4gYWxzbyBjb250YWluIGRhdGEgb3IgcG9pbnQgZGF0YWJhc2UgYXBpIChzdWNoIGB3YnN0YXRzYCB3aGljaCBwb2ludHMgdG8gdGhlIFdvcmxkIEJhbmtzIGRhdGEpLiBSIGhhcyBhbiBleHRyZW1lbHkgcmljaCwgd2VsbCBtYWludGFpbmVkIGVjb3N5c3RlbSBvZiBwYWNrYWdlcyB0aGF0IGNvbnRhaW4gZnVuY3Rpb25zIGFuZCBkYXRhIHRoYXQgYXJlIHJlbGV2YW50IHRvIGFsbW9zdCBhbnkgYWNhZGVtaWMgKG9yIGV2ZW4gdHJpdmlhbCkgdG9waWNzIG9mIGludGVyZXN0LgoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIEluc3RhbGwgdGhlIGZvbGxvd2luZyBwYWNrYWdlcyAtIGB0aWR5dmVyc2VgIGFuZCBgbnljZmxpZ2h0czEzYCB1c2luZyB0aGUgcGFja2FnZSB0YWIgaW4gdGhlIHZpZXdlciBwYW5lICh1c2UgdGhlICFbXShhc3NldHMvaW5zdGFsbC5wbmcpIGJ1dHRvbikKMi4gVXNlIHRoZSBgbGlicmFyeSgpYCBmdW5jdGlvbiB0byBsb2FkIHRoZXNlIHR3byBwYWNrYWdlcyBpbiB0aGUgQ2xhc3MgMSBub3RlYm9vawozLiBDaGVjayB0aGUgcGFja2FnZXMgdGFiIG9uIHlvdXIgdmlld2VyIHRvIHNlZSBpZiB0aGVzZSBwYWNrYWdlcyBhcmUgY2hlY2tlZCAoaS5lLiBsb2FkZWQgdG8gb3VyIGN1cnJlbnQgZW52aXJvbm1lbnQpCjQuIENoZWNrIHRoZSBHbG9iYWwgRW52aXJvbm1lbnQgZHJvcGRvd24gdG8gc2VlIHRoYXQgdGhlc2UgYXJlIGxpc3RlZC4KCjwvZGl2PgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKTsgbGlicmFyeShueWNmbGlnaHRzMTMpCmBgYAoKIyNUaWR5dmVyc2UKVGhlIHRpZHl2ZXJzZSBpcyBhIGNvbGxlY3Rpb24gb2YgcGFja2FnZXMgdGhhdCBmb2xsb3cgdGhlIHRpZHkgdG9vbHMgcGhpbG9zb3BoeS4gCgpbVGhlIFRpZHkgVG9vbHMgTWFuaWZlc3RvXShodHRwczovL3RpZHl2ZXJzZS50aWR5dmVyc2Uub3JnL2FydGljbGVzL21hbmlmZXN0by5odG1sKSBieSBIYWRsZXkgV2lja2hhbSwgZGVzY3JpYmVzIHRoZSBmb3VyIGJhc2ljIHByaW5jaXBsZXMgb2YgYSB0aWR5IEFQSSBhcyBmb2xsb3dzOgoKPjEuIFJldXNlIGV4aXN0aW5nIGRhdGEgc3RydWN0dXJlcy4KMi4gQ29tcG9zZSBzaW1wbGUgZnVuY3Rpb25zIHdpdGggdGhlIHBpcGUuCjMuIEVtYnJhY2UgZnVuY3Rpb25hbCBwcm9ncmFtbWluZy4KNC4gRGVzaWduIGZvciBodW1hbnMuCgpUaGVyZSBhcmUgdHdvIG92ZXJhcmNoaW5nIHByb2dyYW1taW5nIGNvbmNlcHRzIGhlcmUgdGhhdCBhcmUgaW1wb3J0YW50IGZvciB1cyB0byBub3RlIC0gY29tcG9zaXRpb24gYW5kIHRoZSB1c2Ugb2YgZGVjbGFyaXRpdmUgaW5zdGVhZCBvZiBpbXBlcmF0aXZlIGNvZGUuIENvbXBvc2l0aW9uIGlzIHNpbXBseSB0aGUgdXNlIG9mIHNldmVyYWwgc21hbGxlciBmdW5jdGlvbnMgdG8gY3JlYXRlIGEgbW9yZSBjb21wbGV4IGZ1bmN0aW9uLiBUaGUgdGlkeXZlcnNlIGFjaGlldmVzIGNvbXBvc2l0aW9uIHRocm91Z2ggdGhlIHVzZSBvZiBwaXBlcyAoYCU+JWApLiBXZSB3aWxsIGxlYXJuIGFib3V0IHBpcGVzIHJlbGF0aXZlbHkgc29vbi4KCkFjY29yZGluZyB0byBbV2lraXBlZGlhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9EZWNsYXJhdGl2ZV9wcm9ncmFtbWluZyk6Cgo+IEluIGNvbXB1dGVyIHNjaWVuY2UsIGRlY2xhcmF0aXZlIHByb2dyYW1taW5nIGlzIGEgcHJvZ3JhbW1pbmcgcGFyYWRpZ23igJRhIHN0eWxlIG9mIGJ1aWxkaW5nIHRoZSBzdHJ1Y3R1cmUgYW5kIGVsZW1lbnRzIG9mIGNvbXB1dGVyIHByb2dyYW1z4oCUdGhhdCBleHByZXNzZXMgdGhlIGxvZ2ljIG9mIGEgY29tcHV0YXRpb24gd2l0aG91dCBkZXNjcmliaW5nIGl0cyBjb250cm9sIGZsb3cuCgpUaGlzIHZpZGVvIGV4cGxhaW5zIHRoaXMgZnVydGhlciB1c2luZyB0aGUgcmVhbC13b3JsZCBleGFtcGxlIG9mIGEgY2FyIChhbGJlaXQgZnJvbSB0aGUgcGVyc2VwZWN0aXZlIG9mIFJlYWN0IGEgSmF2YXNjcmlwdCBsaWJyYXJ5KS4KPGlmcmFtZSB3aWR0aD0iNTYwIiBoZWlnaHQ9IjMxNSIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC9KWFIycF92dFAzYyIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhdXRvcGxheTsgZW5jcnlwdGVkLW1lZGlhIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CgpUaGUgdGlkeXZlcnNlIHBhY2thZ2VzIGFyZSBjaGFyYWN0ZXJpemVkIGJ5IHRoZWlyIGV4dGVuc2l2ZSB1c2Ugb2YgcGlwZXMgdG8gYnJlYWsgZG93biBjb21wbGV4IGZ1bmN0aW9ucyBpbnRvIHNpbXBsZXIgcGllY2VzIHRoYXQgYXJlIGVhc2llciB0byB0byByZWFkIGFuZCB1bmRlcnN0YW5kLiBXZSB3aWxsIGxlYXJuIGFib3V0IHBpcGVzIHNob3J0bHkuCgrimqEqKipOaW5qYSBUYXNrcyoqKuKaoQoKMS4gUmVhZCB0aGUgW3RpZHkgdG9vbHMgbWFuaWZlc3RvXShodHRwczovL3RpZHl2ZXJzZS50aWR5dmVyc2Uub3JnL2FydGljbGVzL21hbmlmZXN0by5odG1sKQoKCiMjbnljZmxpZ2h0MTMgZGF0YQpXZSB3aWxsIGJlIHVzaW5nIHRoZSBgbnljZmxpZ2h0czEzYCBkYXRhc2V0cyBwYWNrYWdlIHRvIGxlYXJuIGRhdGEgbWFuaXB1bGF0aW9uLiBUaGUgcGFja2FnZSBjb250YWlucyByZWxhdGlvbmFsIGRhdGFzZXRzIHRoYXQgb2ZmZXIgaW5mb3JtYXRpb24gb24gYWxsIHRoZSBmbGlnaHRzIHRoYXQgdG9vayBvZmYgZnJvbSAzIGFpcnBvcnRzIGluIE5ZQyAoRVdSLCBKRkssIExHQSkgaW4gMjAxMy4gVGhlIGRpZmZlcmVudCBkYXRhc2V0cyBpbiB0aGUgcGFja2FnZSBhcmUgYXMgZm9sbG93czoKCjEuIGFpcmxpbmVzOiBOYW1lcyBvZiB0aGUgZGlmZmVyZW50IGFpcmxpbmUgY2FycmllcnMKMi4gYWlycG9ydHM6IE1ldGEgZGF0YSBvbiB0aGUgYWlycG9ydHMgaW4gdGhlIGRhdGFzZXQKMy4gZmxpZ2h0czogRGF0YSBvbiBhbGwgdGhlIGZsaWdodHMgdGhhdCBkZXBhcnRlZCBOWUMgaW4gMjAxMwo0LiBwbGFuZXM6IE1ldGEgZGF0YSBvbiB0aGUgcGxhbmVzICh0aGVpciBtYWtlLCBjYXBhY2l0eSBldGMpCjUuIHdlYXRoZXI6IFdlYXRoZXIgYXQgdGhlIHRocmVlIE5ZQyBhaXJwb3J0cyBvbiBhbGwgZGF5cyBvZiAyMDEzCgpGb3IgdGhpcyBub3RlYm9vayB3ZSB3aWxsIGJlIHVzaW5nIG9ubHkgdGhlIGZsaWdodHMgZGF0YS4KCiMjRGF0YSBNYW5pcHVsYXRpb24gdXNpbmcgZHBseXIKZHBseXIgaXMgYSBwYWNrYWdlIGluIHRoZSB0aWR5dmVyc2UgY29sbGVjdGlvbi4gSXQgcHJvdmlkZXMgZWxlZ2FudCBhbmQgZWFzeSB0byB1bmRlcnN0YW5kIGZ1bmN0aW9ucyBmb3IgbWFuaXB1bGF0aW5nIGRhdGEgaW4gUi4KCktlZXAgdGhpcyBbZGF0YSB3cmFuZ2xpbmddKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzAyL2RhdGEtd3JhbmdsaW5nLWNoZWF0c2hlZXQucGRmKSBjaGVhdHNoZWV0IG9wZW4gb24geW91ciBicm93c2VyIGFzIGEgcmVhZHkgcmVmZXJlbmNlIGZvciB0aGUgcmVzdCBvZiB0aGUgbm90ZWJvb2suCgojIyNUaWJibGVzCgpBIHRpYmJsZSBpcyBhIHRpZHkgdmVyc2lvbiBvZiBhIGRhdGEuZnJhbWUuIEl0IGFkZHMgYSBmZXcgZXh0cmEgZmVhdHVyZXMgKHRocm91Z2ggdHdvIG5ldyBjbGFzc2VzKSB0aGF0IGdpdmUgaXQgYSBmZXcgYWR2YW50YWdlcyBvdmVyIGRhdGEuZnJhbWVzLgoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIENyZWF0ZSBhIHRpYmJsZSAob2YgeW91ciBjaG9pY2UpIHdpdGggdGhyZWUgb2JzZXJ2YXRpb25zIGFuZCB0aHJlZSB2YXJpYWJsZXMuCjIuIFNob3cgdGhlIGNsYXNzIGFuZCBzdHJ1Y3R1cmUgb2YgdGhlIHRpYmJsZSB5b3UgY3JlYXRlZC4KMy4gQ29udmVydCB0aGUgbXRjYXJzIGRhdGEgc2V0IHRvIGEgdGliYmxlLgoK8J+PhioqKlNvbHV0aW9uKioq8J+PhgoKTGV0cyBjcmVhdGUgYSB0aWJibGUgdXNpbmcgdGhlIGB0aWJibGUoKWAgY29tbWFuZC4gQ2hlY2sgb3V0IHRoZSBjb2RlIGJlbG93LiBFYWNoIGlucHV0IGluIHRoZSB0aWJibGUgY29tbWFuZCBpcyBhIGNvbHVtbi4gTm90aWNlIGhvdyBJIGhhdmUgdXNlZCBib3RoIGNvbHVtbiB2ZWN0b3JzIGNyZWF0ZWQgd2l0aGluIGB0aWJibGUoKWAgYW5kIGFuIGV4dGVybmFsbHkgY3JlYXRlZCB0aGUgdmVjdG9yIGBob2JieWAgaW5zaWRlIHRoZSBjb21tYW5kLiAKYGBge3J9CmhvYmJpZXMgPC0gIGMoImRhbmNpbmciLCAiaGlraW5nIiwgInJlYWRpbmciKQpteUZhdm9yaXRlVGhpbmdzIDwtIHRpYmJsZShnYWRnZXRzID0gYygiUGl4ZWwiLCAiS2luZGxlIiwgIlZhY2N1bSBDbGVhbmVyIiksIGJvb2tzID0gYygiRGFzIEthcGl0YWwiLCAiSGFycnkgUG90dGVyIiwgIkVuaWQgQmx5dG9uIiksIGhvYmJpZXMpCgpteUZhdm9yaXRlVGhpbmdzCmBgYAoKCkxldHMgY2hlY2tvdXQgdGhlIHN0cnVjdHVyZSB1c2luZyB0aGUgYHN0cigpYCBjb21tYW5kLgoKYGBge3J9CnN0cihteUZhdm9yaXRlVGhpbmdzKQpgYGAKClRoZSB0aWR5dmVyc2UgYWxzbyBwcm92aWRlcyBhIGZ1bmN0aW9uIGNhbGxlZCBgZ2xpbXBzZSgpYCB0byBkbyB0aGUgc2FtZSB0aGluZyBhcyBgc3RyKClgLiBOb3RpY2UgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIG91dHB1dHMgZnJvbSB0aGUgdHdvIGNvbW1hbmRzLgoKYGBge3J9CmdsaW1wc2UobXlGYXZvcml0ZVRoaW5ncykKYGBgCgpZb3UgY2FuIGFjY2VzcyB0aGUgY2xhc3Mgb2YgYW55IG9iamVjdCBpbiBSIHVzaW5nIHRoZSBgY2xhc3MoKWAgY29tbWFuZC4gTm90aWNlIGhvdyB0aGVyZSBhcmUgdGhyZWUgY2xhc3NlcyBmb3IgYSB0aWJibGUgLSAidGJsX2RmIiwgImRmIiBhbmQgImRhdGEuZnJhbWUiLiBUaWJibGVzIHJlYWxseSBhcmUganVzdCBkYXRhLmZyYW1lcyB3aXRoIHNvbWUgYWRkZWQgZnVuY3Rpb25hbGl0eSBvbiB0b3AgdGhhdCBpcyBwcm92aWRlZCBieSB0aGUgZGYgYW5kIHRibF9kZiBjbGFzc2VzLgpgYGB7cn0KY2xhc3MobXlGYXZvcml0ZVRoaW5ncykKYGBgCgpgbXRjYXJzYCBpcyBhIHBhcnQgb2YgdGhlIGBkYXRhc2V0c2AgcGFja2FnZSB0aGF0IGlzIHByZWxvYWRlZCBpbiBSLiBMZXRzIGZpcnN0IGxvb2sgYXQgaXRzIHN0cnVjdHVyZSB1c2luZyBgc3RyKClgCmBgYHtyfQpzdHIobXRjYXJzKQpgYGAKCkFzIHlvdSBjYW4gc2VlIHRoZSBjbGFzcyBvZiBtdGNhcnMgaXMgYSBkYXRhLmZyYW1lIGFuZCBub3QgYSB0aWJibGUuIFdlIGNhbiBjb252ZXJ0IGl0IHRvIGEgdGliYmxlIHVzaW5nIHRoZSBgYXNfdGliYmxlKClgIGNvbW1hbmQuIEJlbG93LCBJIGhhdmUgdXNlZCB0aGlzIGNvbW1hbmQgdG8gY3JlYXRlIGEgbmV3IHRpYmJsZSBjYWxsZWQgYG10VGliYmxlYC4gVGhlIG91dHB1dCBzaG93cyBpdCBzdHJ1Y3R1cmUuIE5vdGljZSB0aGF0IG5vdyB3ZSBoYXZlIHRoZSB0d28gYWRkaXRpb25hbCBjbGFzc2VzICJkZiIgYW5kICJ0YmxfZGYiIHRoYXQgY2hhcmFjdGVyaXplIHRpYmJsZXMuCgpgYGB7cn0KbXRUaWJibGUgPC0gYXNfdGliYmxlKG10Y2FycykKCnN0cihtdFRpYmJsZSkKYGBgCgoKCiMjI1RoZSBQaXBlIE9wZXJhdG9yCgpUaGUgcGlwZSBvcGVyYXRvciBpcyBhIHBhcnQgb2YgdGhlIGBtYWdpdHRyYCBwYWNrYWdlLiBZb3UgY2FuIGNyZWF0ZSBvbmUgdXNpbmcgdGhlIHNob3J0Y3V0cyB5b3UgbGVhcm50IGVhcmxpZXIgKGBDbWQgKyBTaGlmdCArIE1gIG9yIGBDdHJsICsgU2hpZnQgKyBNYCkuIFRoZSBwaXBlIHRyYW5zZmVycyB0aGUgdmFsdWVzIHRoYXQgYXJlIHRvIHRoZSBsZWZ0IG9mIGl0IHRvIHRoZSByaWdodCBzaWRlLiBXaGlsZSB0aGlzIG1pZ2h0IHNlZW0gYSBiaXQgYWJzdHJhY3QgYXQgdGhpcyBwb2ludCwgYCU+JWAgaXMgYW4gZXhjZWxsZW50IHdheSB0byBicmVhayBkb3duIGNvZGUgaW50byBzbWFsbGVyIHBpZWNlcyB0aGF0IGFyZSBlYXNpZXIgdG8gcmVhZCBhbmQgbWFpbnRhaW4uCgrimqEqKipOaW5qYSBUYXNrcyoqKuKaoQoKMS4gQ2FsY3VsYXRlIHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgc3VtIG9mIGFsbCBldmVuIG51bWJlcnMgZnJvbSAwIHRvIDIwMCBhbmQgY3JlYXRlIGEgc2VxdWVuY2UgdGhhdCBnb2VzIGZyb20gdGhlIHNxdWFyZSByb290IHRvIHR3aWNlIGl0cyB2YWx1ZS4KMi4gUmVwZWF0IHRoZSB0YXNrIHVzaW5nIGJhc2UgY29tbWFuZHMuCgrwn4+GKioqU29sdXRpb24qKirwn4+GCgpGaXJzdCBsZXRzIGRvIGl0IHVzaW5nIHBpcGVzLiBOb3RpY2UgdGhlIHVzZSBvZiB0aGUgZG90IG9uIHRoZSBsYXN0IGxpbmUgb2YgdGhlIGNvZGUuIFdoZW4gdXNpbmcgcGlwZXMgdGhlIGAuYCBpcyB1c2VkIHRvIHJlZmVyIGV4cGxpY2l0bHkgdG8gdGhlIGRhdGEgb24gdGhlIGxlZnQgc2lkZSBvZiB0aGUgcGlwZS4gV2UgZG8gdGhpcyBzbyB0aGF0IHdlIGNhbiBwZXJmb3JtIG9wZXJhdGlvbiBvbiBpdC4gSW4gb3VyIGNhc2UsIHdlIG5lZWQgdG8gY3JlYXRlIGEgc2VxdWVuY2UgdGhhdCBnb2VzIGZyb20gdGhlIGxlZnQtaGFuZCBzaWRlIHZhbHVlIHRvIHR3aWNlIGl0cyB2YWx1ZSBhbmQgd2UgYWNoZWl2ZSB0aGlzIHVzaW5nIGAuICogMmAuIE5vdGUgdGhhdCB3ZSBjb3VsZCBoYXZlIHVzZWQgdGhlIGRvdCBub3RhdGlvbiB0byByZWZlciB0byB0aGUgZGF0YSBvbiB0aGUgbGVmdCBoYW5kIHNpZGUgZXhwbGljaXRseSBmb3IgZWFjaCBjb21tYW5kLCBob3dldmVyLCBkcGx5ciBhdXRvbWF0aWNhbGx5IGFzc3VtZXMgdGhhdCB5b3UgYXJlIHBhc3NpbmcgdGhlIGRhdGEgZnJvbSB0aGUgbGVmdCBzaWRlIHNhdmluZyB1cyB0aGUgdHJvdWJsZS4gV2Ugb25seSBuZWVkIHRvIHVzZSBhIGAuYCBpZiB3ZSBuZWVkIHRvIHBlcmZvcm0gYW4gb3BlcmF0aW9uIG9yIHVzZSBpdCBleHBsaWNpdGx5IGFzIGEgZnVuY3Rpb24gYXJndW1lbnQuCmBgYHtyfQojI2NyZWF0ZSBhIHNlcXVlbmNlIG9mIGV2ZW4gbnVtYmVycyBmcm9tIDAgdG8gMjAwCnNlcShmcm9tID0gMCwgdG8gPSAyMDAsIGJ5ID0gMikgJT4lIAogICAgIyNjYWxjdWxhdGUgdGhlIHN1bSBvZiBhbGwgdmFsdWVzIGluIHRoZSBwcmV2aW91cyB2ZWN0b3IKICAgIHN1bSgpICU+JSAKICAgICMjY2FsY3VsYXRlIHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgdmFsdWUgZnJvbSB0aGUgc3VtIG9wZXJhdGlvbgogICAgc3FydCgpICU+JSAKICAgICMjY3JlYXRlIGEgbmV3IHNlcSBmcm9tIHRoZSBwcmV2aW91cyB2YWx1ZSB0byB0d2ljZSBpdHMgdmFsdWUKICAgIHNlcShmcm9tID0gLiwgdG8gPSAuICogMiwgYnkgPSAyKQpgYGAKCk5vdyBsZXRzIGRvIHRoaXMgd2l0aG91dCB0aGUgcGlwZXMuIE5vdGljZSBob3cgdGhlIGJhc2UgY29tbWFuZCBjb21iaW5lcyBtdWx0aXBsZSBzdGVwcyBpLmUuIGBzdW0oKWAsIGBzcXJ0KClgIGFuZCBgc2VxKClgIGludG8gYSBzaW5nbGUgY29tbWFuZC4gQ29kZSBzdWNoIGFzIHRoaXMgaXMgaGFyZGVyIHRvIHJlYWQsIHVuZGVyc3RhbmQgYW5kIGRlYnVnIGNvbXBhcmVkIHRvIHRoZSB2ZXJzaW9uIHRoYXQgdXNlcyBgJT4lYC4KYGBge3J9CiMjY3JlYXRlIHRoZSBhIHNlcXVlbmNlLCBjYWxjdWxhdGUgaXRzIHN1bSBhbmQgZmluZCB0aGUgc3F1YXJlIHJvb3QKc3FydFZhbHVlIDwtIHNxcnQoc3VtKHNlcShmcm9tID0gMSwgdG8gPSAyMDAsIGJ5ID0gMikpKQojI2NyZWF0ZSBhIHNlcXVlbmNlCnNlcShmcm9tID0gc3FydFZhbHVlLCB0byA9IDIgKiBzcXJ0VmFsdWUsIGJ5ID0gMikKYGBgCgoKIyMjRmlsdGVyCgpGaWx0ZXIgaXMgdGhlIGRwbHlyIHZlcmIgZm9yIHN1YnNldHRpbmcgcm93cyBvZiBkYXRhIGJhc2VkIG9uIGEgcGFydGljdWxhciBjb25kaXRpb24uCgoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIFdoaWNoIGZsaWdodCBvdXQgb2YgSkZLIHdhcyB0aGUgbW9zdCBkZWxheWVkIGluIDIwMTM/CjIuIEFuc3dlciB0aGUgcHJldmlvdXMgcXVlc3Rpb24gd2l0aG91dCB1c2luZyBkcGx5ciBvciBwaXBlcy4KMy4gV2hhdCB3ZXJlIHRoZSA1IGxvbmdlc3QgZmxpZ2h0cyAoaW4gYWlyIHRpbWUpIGZyb20gTllDIGluIDIwMTM/Cgrwn4+GKioqU29sdXRpb24qKirwn4+GCgpMZXRzIGZpbmQgdGhlIG1vc3QgZGVsYXllZCBmbGlnaHQgb3V0IG9mIEpGSwpgYGB7cn0KZmxpZ2h0cyAlPiUgCiAgICAjI2ZpbHRlciBhbGwgZmxpZ2h0cyBmcm9tIEpGSwogICAgZmlsdGVyKG9yaWdpbiA9PSAiSkZLIikgJT4lIAogICAgIyNmaW5kIHRoZSBmbGlnaHQgdGhhdCBoYWQgdGhlIG1heGltdW0gZGVwYXJ0dXJlIGRlbGF5CiAgICBmaWx0ZXIoZGVwX2RlbGF5ID09IG1heChkZXBfZGVsYXksIG5hLnJtID0gVCkpCmBgYAoKTGV0cyB0cnkgdG8gZG8gdGhpcyB1c2luZyBiYXNlIFIuIE5vdGljZSBob3cgdGhlIGNvZGUgaXMgZmFyIGxlc3MgcmVhZGFibGUgaW4gdGhpcyBjYXNlLgpgYGB7cn0KamZrRmxpZ2h0cyA8LSBmbGlnaHRzW2ZsaWdodHMkb3JpZ2luID09ICJKRksiLCBdCgptYXhEZWxheSA8LSBtYXgoamZrRmxpZ2h0cyRkZXBfZGVsYXksIG5hLnJtID0gVCkKCmpma0ZsaWdodHNbamZrRmxpZ2h0cyRkZXBfZGVsYXkgPT0gbWF4RGVsYXkgJiAhaXMubmEoamZrRmxpZ2h0cyRkZXBfZGVsYXkpLCBdCmBgYAoKZHBseXIgYWxzbyBzaGlwcyB3aXRoIGhlbHBlciBmdW5jdGlvbi4gV2UgY2FuIHVzZSBvbmUgb2YgdGhlc2UgYHRvcF9uYCB0byBmaW5kIHRoZSBmbGlnaHRzIHRoYXQgaGFkIHRoZSBoaWdoZXN0IGFpciB0aW1lcy4KCmBgYHtyfQpmbGlnaHRzICU+JSAKICAgIHRvcF9uKGFpcl90aW1lLCBuID0gNSkKYGBgCgoKIyMjU2VsZWN0CgpTZWxlY3QgaXMgYSBkcGx5ciB2ZXJiIHRoYXQgaXMgdXNlZCBmb3Igc3Vic2V0dGluZyBjb2x1bW5zLgoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIFNlbGVjdCBhbGwgdGhlIGNvbHVtbnMgdGhhdCBhcmUgcmVsZXZhbnQgZm9yIGFycml2YWwgYW5kIGRlcGFydHVyZSBkZWxheXMgdXNpbmcgYSB1dGlsaXR5IGZ1bmN0aW9uIChyZWZlciB0byBjaGVhdCBzaGVldCkKCgrwn4+GKioqU29sdXRpb24qKirwn4+GCgpXZSBjYW4gY29tYmluZSB0aGUgc2VsZWN0IHZlcmIgd2l0aCB0aGUgYGNvbnRhaW5gIGhlbHBlciBmdW5jdGlvbiB0byBhY2hpZXZlIHRoaXMgdGFzay4KYGBge3J9CmZsaWdodHMgJT4lIAogICAgc2VsZWN0KGNvbnRhaW5zKCJkZWxheSIpKQpgYGAKCgojIyNBcnJhbmdlCkFycmFuZ2UgaXMgYSB2ZXJiIHRoYXQgYXJyYW5nZXMgdGhlIHJvd3MgYmFzZWQgb24gdGhlIHZhbHVlcyBvZiBhIHBhcnRpY3VsYXIgY29sdW1uIGkuZS4gcGVyZm9ybXMgYSBzb3J0LgoK4pqhKioqTmluamEgVGFza3MqKirimqEKCjEuIEZpbHRlciB0aGUgdG9wIDEwIG1vc3QgZGVsYXllZCBmbGlnaHRzIGluIEpGSyBhbmQgYXJyYW5nZSBieSBkZXBfZGVsYXkgKGhpZ2hlc3QgdG8gbG93ZXN0KQoK8J+PhioqKlNvbHV0aW9uKioq8J+PhgoKTm90ZSB0aGF0IEkgaGF2ZSAKYGBge3J9CmZsaWdodHMgJT4lIAogICAgIyNhcnJhbmdlIGRlcF9kZWxheSBpbiBkZXNjZW5kaW5nIG9yZGVyIChoaWdoIHRvIGxvdykKICAgIGFycmFuZ2UoZGVzYyhkZXBfZGVsYXkpKSAlPiUgCiAgICAjI2ZpbHRlciB0aGUgZmlyc3QgMTAgcm93cyB1c2luZyByb3dfbnVtYmVyKCkKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgPD0gMTApICU+JSAKICAgICMjc2VsZWN0IHRoZSByZWxldmFudCBjb2x1bW5zCiAgICBzZWxlY3QobW9udGgsIGRheSwgb3JpZ2luLCBkZXBfZGVsYXkpCmBgYAoKCiMjI011dGF0ZQpNdXRhdGUgY2hhbmdlcyBhIHRpYmJsZSBieSBhZGRpbmcgYSBuZXcgY29sdW1uIHZlY3RvciBvciBjaGFuZ2luZyBhbiBleGlzdGluZyBvbmUuCgrimqEqKipOaW5qYSBUYXNrcyoqKuKaoQoKMS4gQ3JlYXRlIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCB0b3RhbF9kZWxheSB0aGF0IGlzIHRoZSBzdW0gb2YgdGhlIGFycml2YWwgZGVsYXkgYW5kIGRlcGFydHVyZSBkZWxheQoyLiBEbyB0aGUgc2FtZSB0YXNrIHVzaW5nIEJhc2UgUgoK8J+PhioqKlNvbHV0aW9uKioq8J+PhgoKYGBge3J9CmZsaWdodHMgJT4lIAogICAgIyNjb21iaW5lIGFycml2YWwgZGVsYXkgYW5kIGRlcGFydHVyZSBkZWxheQogICAgbXV0YXRlKHRvdF9kZWxheSA9IGFycl9kZWxheSArIGRlcF9kZWxheSkgJT4lIAogICAgIyNzZWxlY3QgYWxsIHRoZSBkZWxheSBjb2x1bW5zCiAgICBzZWxlY3QoY29udGFpbnMoImRlbGF5IikpCmBgYAoKTm93IGxldHMgcmVwZWF0IHRoaXMgdXNpbmcgQmFzZSBSLgpgYGB7cn0KZmxpZ2h0cyR0b3RfZGVsYXkgPC0gZmxpZ2h0cyRhcnJfZGVsYXkgKyBmbGlnaHRzJGRlcF9kZWxheQoKZmxpZ2h0c1tuYW1lcyhmbGlnaHRzKSAlaW4lIGMoImRlcF9kZWxheSIsICJhcnJfZGVsYXkiLCAidG90X2RlbGF5IildCmBgYAoKCiMjI0dyb3VwIGFuZCBTdW1tYXJpc2UKYGdyb3VwX2J5KClgIGNhdGVnb3JpemVzIHRoZSBkYXRhIGJhc2VkIG9uIHRoZSBncm91cGluZyB2YXJpYWJsZSwgd2hpbGUgc3VtbWFyaXNlIGNhbGN1bGF0ZXMgc3VtbWFyeSBzdGF0aXN0aWNzIHdpdGhpbiB0aGVzZSBncm91cHMuCgrimqEqKipOaW5qYSBUYXNrcyoqKuKaoQoKMS4gQ3JlYXRlIGEgc3VtbWFyeSB0YWJsZSB3aXRoIHRoZSBmb2xsb3dpbmcgY2hhcmFjdGVyaXN0aWNzIGZvciBlYWNoIG9mIHRoZSBvcmlnaW4gYWlycG9ydHMuCiAgICArIE51bWJlciBvZiBmbGlnaHRzCiAgICArIE51bWJlciBvZiB1bmlxdWUgY2FycmllcnMKICAgICsgQXZlcmFnZSBkZXBhcnR1cmUgZGVsYXlzCiAgICArIEF2ZXJhZ2UgZmxpZ2h0IHRpbWVzIChhaXIgdGltZSkKICAgICsgQXZlcmFnZSBhcnJpdmFsIGRlbGF5cwoK8J+PhioqKlNvbHV0aW9uKioq8J+PhgoKTm90ZSB0aGUgdXNlIG9mIHRoZSBmdW5jdGlvbnMgYG4oKWAgYW5kIGBuX2Rpc3RpbmN0KClgLiBMb29rIHVwIHRoZSBoZWxwIHRvIHVuZGVyc3RhbmQgd2hhdCB0aGV5IGRvLgpgYGB7cn0KZmxpZ2h0cyAlPiUgCiAgICAjI2dyb3VwIHRoZSBkYXRhIGJ5IHRoZSBvcmlnaW4gKEpGSywgRVdSLCBMR0EpCiAgICBncm91cF9ieShvcmlnaW4pICU+JSAKICAgICMjY2FsY3VsYXRlIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgaW50ZXJlc3QKICAgIHN1bW1hcmlzZShuRmxpZ2h0cyA9IG4oKSwKICAgICAgICAgICAgICBuQ2FycmllcnMgPSBuX2Rpc3RpbmN0KGNhcnJpZXIpLAogICAgICAgICAgICAgIG1lYW5EZXBEZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFQpLAogICAgICAgICAgICAgIG1lYW5BaXJUaW1lID0gbWVhbihhaXJfdGltZSwgbmEucm0gPSBUKSwKICAgICAgICAgICAgICBtZWFuQXJyRGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUKSkKICAgIApgYGAKCiAgCgoKCg==